package net.yongjinman.app.android.util;

import java.util.ArrayList;

import android.view.MotionEvent;

public class TouchEventManager {
	/** instance */
	private static TouchEventManager gInstance = null;
	
	private int mnPointerCount = 0;
	private ArrayList<TouchEventPointer> mAryPointer = null;

	public static final int EVENT_ACTION_NONE = 0x00000000;
	public static final int EVENT_ACTION_DOWN = 0x00010000;
	public static final int EVENT_ACTION_SINGLETAPUP = 0x00020000;
	public static final int EVENT_ACTION_SINGLETAPCONFIRMED = 0x00040000;
	public static final int EVENT_ACTION_SHOWPRESS = 0x00080000;
	public static final int EVENT_ACTION_LONGPRESS = 0x00100000;
	public static final int EVENT_ACTION_SCROLL = 0x00200000;
	public static final int EVENT_ACTION_FLING = 0x00400000;
	public static final int EVENT_ACTION_DOUBLETAP = 0x00800000;

	private int mnEventAction = EVENT_ACTION_NONE;
	
	private TouchEventManager() {
		mAryPointer = new ArrayList<TouchEventPointer>();
		init();
	}
	
	public static TouchEventManager getInstance() {
		if(gInstance == null) {
			gInstance = new TouchEventManager();
		}
		return gInstance;
	}

	public void init() {
		setPointerCount(0);
		if(!mAryPointer.isEmpty()) {
			mAryPointer.clear();
		}
	}
	
	public boolean setTouchEventState(MotionEvent ev) {
		boolean retValue = false;
		int nPointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
		int nPointerId = ev.getPointerId(nPointerIndex);
		setPointerCount(ev.getPointerCount());
		if(nPointerId < 0) {
			PrintLog.printUIError("setTouchEventState Error pointer id [id="+nPointerId+"]");
			return retValue;
		}
		while(mAryPointer.size() <= nPointerId) {
			mAryPointer.add(new TouchEventPointer());
		}
		TouchEventPointer pointer = mAryPointer.get(nPointerId);
		if(pointer == null) {
			PrintLog.printUIError("setTouchEventState pointer error [id="+nPointerId+"]");
			return retValue;
		}
		pointer.setPointerId(nPointerId);
		pointer.setDownTime(ev.getDownTime());
		pointer.setEventTime(ev.getEventTime());
		pointer.setCurrentPos(ev.getX(), ev.getY());
		switch(ev.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN :
			pointer.setDownPos(ev.getX(), ev.getY());
			break;
		case MotionEvent.ACTION_MOVE :
			break;
		case MotionEvent.ACTION_UP :
			pointer.setUpPos(ev.getX(), ev.getY());
			break;
		case MotionEvent.ACTION_POINTER_DOWN :
			pointer.setDownPos(ev.getX(), ev.getY());
			break;
		case MotionEvent.ACTION_POINTER_UP :
			break;
		default :
			break;
		}
		retValue = true;
		pointer.printLog("setTouchEventState [count="+getPointerCount()+"][action="+(ev.getAction() & MotionEvent.ACTION_MASK)+"]");
		return retValue;
	}
	
	public boolean isMultiTouch() {
		boolean retValue = false;
		if(getPointerCount() > 1) {
			retValue = true;
		}
		PrintLog.printUI("D", 3, "isMultiTouch [retValue="+retValue+"]");
		return retValue;
	}

	public void setPointerCount(int pointerCount) {
		mnPointerCount = pointerCount;
	}
	public int getPointerCount() {
		return mnPointerCount;
	}

	public float getDownPosX(int pointerId) {
		float retValue = 0;
		if(pointerId < 0) {
			PrintLog.printUIError("getDownPosX Error pointer id [id="+pointerId+"]");
			return retValue;
		}
		if(mAryPointer.size() <= pointerId) {
			PrintLog.printUIError("getDownPosX Error pointer arry error [list size="+mAryPointer.size()+"][pointer id="+pointerId+"]");
			return retValue;
		}
		TouchEventPointer pointer = mAryPointer.get(pointerId);
		retValue = pointer.getDownPosX();
		return retValue;
	}
	public float getDownPosY(int pointerId) {
		float retValue = 0;
		if(pointerId  < 0) {
			PrintLog.printUIError("getDownPosY Error pointer id [id="+pointerId+"]");
			return retValue;
		}
		if(mAryPointer.size() <= pointerId) {
			PrintLog.printUIError("getDownPosY Error pointer arry error [list size="+mAryPointer.size()+"][pointer id="+pointerId+"]");
			return retValue;
		}
		TouchEventPointer pointer = mAryPointer.get(pointerId);
		retValue = pointer.getDownPosY();
		return retValue;
	}

	public float getMoveX(int pointerId) {
		float retValue = 0;
		if(pointerId < 0) {
			PrintLog.printUIError("getMoveX Error pointer id [id="+pointerId+"]");
			return retValue;
		}
		if(mAryPointer.size() <= pointerId) {
			PrintLog.printUIError("getMoveX Error pointer arry error [list size="+mAryPointer.size()+"][pointer id="+pointerId+"]");
			return retValue;
		}
		TouchEventPointer pointer = mAryPointer.get(pointerId);
		retValue = Math.abs(pointer.getDownPosX()-pointer.getCurrentPosX());
		PrintLog.printUI("D", 3, "getMoveX [retValue="+retValue+"]");
		return retValue;
	}
	public float getMoveY(int pointerId) {
		float retValue = 0;
		if(pointerId < 0) {
			PrintLog.printUIError("getMoveY Error pointer id [id="+pointerId+"]");
			return retValue;
		}
		if(mAryPointer.size() <= pointerId) {
			PrintLog.printUIError("getMoveY Error pointer arry error [list size="+mAryPointer.size()+"][pointer id="+pointerId+"]");
			return retValue;
		}
		TouchEventPointer pointer = mAryPointer.get(pointerId);
		retValue = Math.abs(pointer.getDownPosY()-pointer.getCurrentPosY());
		PrintLog.printUI("D", 3, "getMoveY [retValue="+retValue+"]");
		return retValue;
	}

	public void setEventAction(int action) {
		mnEventAction = action;
		printEvent("setEventAction [action="+action+"]");
	}
	public void addEventAction(int action) {
		mnEventAction |= action;
		printEvent("addEventAction  [action="+action+"]");
	}
	public int getEventAction() {
		return mnEventAction;
	}
	
	public void printEvent(String strTag) {
		StringBuffer strBuf = new StringBuffer();
		StackTraceElement[] stacks = new Throwable().getStackTrace();
		String caller = stacks[1].getClassName()+"."+stacks[1].getMethodName()+"."+stacks[1].getLineNumber();
		strBuf.append(strTag).append(" ");
		if((mnEventAction & EVENT_ACTION_DOWN) != 0) {
			strBuf.append("| EVENT_ACTION_DOWN");
		}
		if((mnEventAction & EVENT_ACTION_SINGLETAPUP) != 0) {
			strBuf.append("| EVENT_ACTION_SINGLETAPUP");
		}
		if((mnEventAction & EVENT_ACTION_SINGLETAPCONFIRMED) != 0) {
			strBuf.append("| EVENT_ACTION_SINGLETAPCONFIRMED");
		}
		if((mnEventAction & EVENT_ACTION_SHOWPRESS) != 0) {
			strBuf.append("| EVENT_ACTION_SHOWPRESS");
		}
		if((mnEventAction & EVENT_ACTION_LONGPRESS) != 0) {
			strBuf.append("| EVENT_ACTION_LONGPRESS");
		}
		if((mnEventAction & EVENT_ACTION_SCROLL) != 0) {
			strBuf.append("| EVENT_ACTION_SCROLL");
		}
		if((mnEventAction & EVENT_ACTION_FLING) != 0) {
			strBuf.append("| EVENT_ACTION_FLING");
		}
		if((mnEventAction & EVENT_ACTION_DOUBLETAP) != 0) {
			strBuf.append("| EVENT_ACTION_DOUBLETAP");
		}
		strBuf.append(" |");
		PrintLog.print("I", PrintLog.LOG_PART_UI, 4, strBuf.toString(), caller);
	}
	
	public void printLog(String strTag) {
		StringBuffer strBuf = new StringBuffer();
		StackTraceElement[] stacks = new Throwable().getStackTrace();
		String caller = stacks[1].getClassName()+"."+stacks[1].getMethodName()+"."+stacks[1].getLineNumber();
		strBuf.append(strTag).append(" ");
		strBuf.append("[pointer count=").append(getPointerCount()).append("]");
		PrintLog.print("I", PrintLog.LOG_PART_UI, 4, strBuf.toString(), caller);
	}

	public class TouchEventPointer {
		private int mnPointerId = -1;
		private float mfDownPosX = 0;
		private float mfDownPosY = 0;
		private float mfCurrentPosX = 0;
		private float mfCurrentPosY = 0;
		private float mfUpPosX = 0;
		private float mfUpPosY = 0;
		private long mlDownTime = 0L;
		private long mlEventTime = 0L;
		
		public TouchEventPointer() {
			init();
		}
		
		public void init() {
			setPointerId(-1);
			setDownPos(0, 0);
			setCurrentPos(0, 0);
			setUpPos(0, 0);
			setDownTime(0L);
			setEventTime(0L);
		}

		public void setPointerId(int pointerId) {
			mnPointerId = pointerId;
		}
		public int getPointerId() {
			return mnPointerId;
		}

		public void setDownPos(float downPosX, float downPosY) {
			setDownPosX(downPosX);
			setDownPosY(downPosY);
		}
		public void setDownPosX(float downPosX) {
			mfDownPosX = downPosX;
		}
		public void setDownPosY(float downPosY) {
			mfDownPosY = downPosY;
		}
		public float getDownPosX() {
			return mfDownPosX;
		}
		public float getDownPosY() {
			return mfDownPosY;
		}

		public void setCurrentPos(float currentPosX, float currentPosY) {
			setCurrentPosX(currentPosX);
			setCurrentPosY(currentPosY);
		}
		public void setCurrentPosX(float currentPosX) {
			mfCurrentPosX = currentPosX;
		}
		public void setCurrentPosY(float currentPosY) {
			mfCurrentPosY = currentPosY;
		}
		public float getCurrentPosX() {
			return mfCurrentPosX;
		}
		public float getCurrentPosY() {
			return mfCurrentPosY;
		}

		public void setUpPos(float upPosX, float upPosY) {
			setUpPosX(upPosX);
			setUpPosY(upPosY);
		}
		public void setUpPosX(float upPosX) {
			mfUpPosX = upPosX;
		}
		public void setUpPosY(float upPosY) {
			mfUpPosY = upPosY;
		}
		public float getUpPosX() {
			return mfUpPosX;
		}
		public float getUpPosY() {
			return mfUpPosY;
		}

		public void setDownTime(long downTime) {
			mlDownTime = downTime;
		}
		public long getDownTime() {
			return mlDownTime;
		}

		public void setEventTime(long eventTime) {
			mlEventTime = eventTime;
		}
		public long getEventTime() {
			return mlEventTime;
		}

		public void printLog(String strTag) {
			StringBuffer strBuf = new StringBuffer();
			StackTraceElement[] stacks = new Throwable().getStackTrace();
			String caller = stacks[1].getClassName()+"."+stacks[1].getMethodName()+"."+stacks[1].getLineNumber();
			strBuf.append(strTag).append(" ");
			strBuf.append("[mnPointerId=").append(getPointerId()).append("]");
			strBuf.append("[mfDownPosX=").append(getDownPosX()).append("]");
			strBuf.append("[mfDownPosY=").append(getDownPosY()).append("]");
			strBuf.append("[mfCurrentPosX=").append(getCurrentPosX()).append("]");
			strBuf.append("[mfCurrentPosY=").append(getCurrentPosY()).append("]");
			strBuf.append("[mfUpPosX=").append(getUpPosX()).append("]");
			strBuf.append("[mfUpPosY=").append(getUpPosY()).append("]");
			strBuf.append("[mlDownTime=").append(getDownTime()).append("]");
			strBuf.append("[mlEventTime=").append(getEventTime()).append("]");
			PrintLog.print("I", PrintLog.LOG_PART_UI, 4, strBuf.toString(), caller);
		}
	}
}
